package org.example.ding.service;

import org.example.ding.dto.DishCategoryDto;
import org.example.ding.entity.DishCategory;
import org.example.ding.repository.DishCategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 菜品分类服务层
 */
@Service
@Transactional
public class DishCategoryService {

    @Autowired
    private DishCategoryRepository dishCategoryRepository;

    /**
     * 创建菜品分类
     */
    public DishCategory createCategory(DishCategoryDto categoryDto) {
        // 检查分类名称是否已存在
        if (dishCategoryRepository.existsByName(categoryDto.getName())) {
            throw new RuntimeException("分类名称已存在");
        }

        DishCategory category = categoryDto.toDishCategory();
        return dishCategoryRepository.save(category);
    }

    /**
     * 更新菜品分类
     */
    public DishCategory updateCategory(Long categoryId, DishCategoryDto categoryDto) {
        DishCategory category = dishCategoryRepository.findById(categoryId)
            .orElseThrow(() -> new RuntimeException("菜品分类不存在"));

        // 如果名称发生变化，检查新名称是否已被使用
        if (categoryDto.getName() != null && !categoryDto.getName().equals(category.getName())) {
            if (dishCategoryRepository.existsByName(categoryDto.getName())) {
                throw new RuntimeException("分类名称已被其他分类使用");
            }
        }

        // 更新分类信息
        categoryDto.updateDishCategory(category);

        return dishCategoryRepository.save(category);
    }

    /**
     * 删除菜品分类
     */
    public void deleteCategory(Long categoryId) {
        DishCategory category = dishCategoryRepository.findById(categoryId)
            .orElseThrow(() -> new RuntimeException("菜品分类不存在"));

        // 检查是否有菜品使用此分类
        if (category.getDishes() != null && !category.getDishes().isEmpty()) {
            throw new RuntimeException("该分类下还有菜品，无法删除");
        }

        dishCategoryRepository.delete(category);
    }

    /**
     * 根据ID查找分类
     */
    @Transactional(readOnly = true)
    public Optional<DishCategory> findById(Long categoryId) {
        return dishCategoryRepository.findById(categoryId);
    }

    /**
     * 根据名称查找分类
     */
    @Transactional(readOnly = true)
    public Optional<DishCategory> findByName(String name) {
        return dishCategoryRepository.findByName(name);
    }

    /**
     * 获取所有分类
     */
    @Transactional(readOnly = true)
    public List<DishCategory> getAllCategories() {
        return dishCategoryRepository.findAllByOrderByName();
    }

    /**
     * 根据餐别类型获取分类
     */
    @Transactional(readOnly = true)
    public List<DishCategory> getCategoriesByMealType(DishCategory.MealType mealType) {
        return dishCategoryRepository.findByMealTypeOrderByName(mealType);
    }

    /**
     * 获取所有分类的DTO列表
     */
    @Transactional(readOnly = true)
    public List<DishCategoryDto> getAllCategoryDtos() {
        return dishCategoryRepository.findAllByOrderByName().stream()
            .map(DishCategoryDto::fromDishCategory)
            .collect(Collectors.toList());
    }

    /**
     * 根据餐别类型获取分类DTO列表
     */
    @Transactional(readOnly = true)
    public List<DishCategoryDto> getCategoryDtosByMealType(DishCategory.MealType mealType) {
        return dishCategoryRepository.findByMealTypeOrderByName(mealType).stream()
            .map(DishCategoryDto::fromDishCategory)
            .collect(Collectors.toList());
    }

    /**
     * 获取分类及其菜品数量统计
     */
    @Transactional(readOnly = true)
    public List<CategoryWithCount> getCategoriesWithDishCount() {
        List<Object[]> results = dishCategoryRepository.findCategoriesWithDishCount();
        return results.stream()
            .map(result -> new CategoryWithCount(
                (Long) result[0],
                (String) result[1],
                ((Number) result[2]).longValue()
            ))
            .collect(Collectors.toList());
    }

    /**
     * 检查分类名称是否可用
     */
    @Transactional(readOnly = true)
    public boolean isCategoryNameAvailable(String name) {
        return !dishCategoryRepository.existsByName(name);
    }

    /**
     * 检查分类名称是否可用（排除指定ID）
     */
    @Transactional(readOnly = true)
    public boolean isCategoryNameAvailable(String name, Long excludeId) {
        Optional<DishCategory> existingCategory = dishCategoryRepository.findByName(name);
        return existingCategory.isEmpty() || existingCategory.get().getId().equals(excludeId);
    }

    /**
     * 初始化默认分类
     */
    public void initializeDefaultCategories() {
        // 检查是否已有分类
        if (dishCategoryRepository.count() > 0) {
            return;
        }

        // 创建默认分类
        createDefaultCategory("主食", "米饭、面条、面包等主食类", DishCategory.MealType.LUNCH);
        createDefaultCategory("汤品", "各种汤类菜品", DishCategory.MealType.LUNCH);
        createDefaultCategory("素菜", "蔬菜类菜品", DishCategory.MealType.LUNCH);
        createDefaultCategory("荤菜", "肉类菜品", DishCategory.MealType.LUNCH);
        createDefaultCategory("早餐", "早餐专用菜品", DishCategory.MealType.BREAKFAST);
        createDefaultCategory("晚餐", "晚餐专用菜品", DishCategory.MealType.DINNER);
        createDefaultCategory("小食", "零食和小点心", DishCategory.MealType.SNACK);
    }

    /**
     * 创建默认分类
     */
    private void createDefaultCategory(String name, String description, DishCategory.MealType mealType) {
        if (!dishCategoryRepository.existsByName(name)) {
            DishCategory category = new DishCategory();
            category.setName(name);
            category.setDescription(description);
            category.setMealType(mealType);
            dishCategoryRepository.save(category);
        }
    }

    /**
     * 分类及菜品数量统计内部类
     */
    public static class CategoryWithCount {
        private final Long categoryId;
        private final String categoryName;
        private final Long dishCount;

        public CategoryWithCount(Long categoryId, String categoryName, Long dishCount) {
            this.categoryId = categoryId;
            this.categoryName = categoryName;
            this.dishCount = dishCount;
        }

        public Long getCategoryId() { return categoryId; }
        public String getCategoryName() { return categoryName; }
        public Long getDishCount() { return dishCount; }
    }
}
